﻿#include "QCefRenderClient.h"

QCefRenderClient::QCefRenderClient(QCefApp* app)
    : m_app(app)
{
    QCEF_DEBUG();

    //
    if (m_app != nullptr)
    {
        m_app->checkInClient(this);
    }
}


QCefRenderClient::~QCefRenderClient()
{
    QCEF_DEBUG();

    m_reportFunc = nullptr;
    m_v8Handler = nullptr;
    m_frame = nullptr;
    m_browser = nullptr;

    //
    if (m_app != nullptr)
    {
        m_app->checkOutClient(this);
    }
    m_app = nullptr;
}


int QCefRenderClient::init(CefRefPtr<CefBrowser> browser,
                           CefRefPtr<CefFrame> frame,
                           CefRefPtr<CefV8Context> context)
{
    QCEF_DEBUG();

    m_browser = browser;
    m_frame = frame;

    //
    CefRefPtr<CefV8Value> global = context->GetGlobal();

    //
    m_v8Handler = new QCefV8Handler(this);

    //ReportJSResultFunction
    m_reportFunc = CefV8Value::CreateFunction(kQCefReportJavaScriptResultFunctionName, m_v8Handler);
    global->SetValue(kQCefReportJavaScriptResultFunctionName, m_reportFunc, V8_PROPERTY_ATTRIBUTE_NONE);

    return 0;
}


void QCefRenderClient::AsyncExecuteNativeMethod(const CefV8ValueList& arguments)
{
    QCEF_DEBUG();

    //** arguments(CefValueList)
    //** +-------+
    //** |0 name | <- the method name
    //** |1 arg1 |
    //** |2 arg2 |
    //** | ...   |
    //** +-------+

    CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create(kQCefRenderInvokeMethodMessage);

    CefRefPtr<CefListValue> args = msg->GetArgumentList();

    // push back all the arguments
    for (std::size_t i = 0; i < arguments.size(); i++)
    {
        CefRefPtr<CefValue> cefValue = V8ValueToCefValue(arguments[i].get());
        args->SetValue(i, cefValue);
    }

    // send the message
    if (m_browser != nullptr && m_frame != nullptr)
    {
        m_frame->SendProcessMessage(PID_BROWSER, msg);
    }
}

void QCefRenderClient::reportJavaScriptResult(const CefV8ValueList& arguments)
{
    QCEF_DEBUG();

    //** arguments(CefValueList)
    //** +_------+
    //** |0 arg  | <- the context id
    //** |1 arg  | <- the result value
    //** +-------+

    CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create(kQCefRenderReportJavaScriptResultMessage);

    CefRefPtr<CefListValue> args = msg->GetArgumentList();

    // push back the result value
    for (std::size_t i = 0; i < arguments.size(); i++)
    {
        CefRefPtr<CefValue> cefValue = V8ValueToCefValue(arguments[i].get());
        args->SetValue(i, cefValue.get());
    }

    // send the message
    if (m_browser != nullptr && m_frame != nullptr)
    {
        m_frame->SendProcessMessage(PID_BROWSER, msg);
    }
}

//CefRefPtr<CefV8Value> QCefRenderClient::CefValueToV8Value(CefValue* cefValue)
//{
//    QCEF_DEBUG();

//    CefRefPtr<CefV8Value> v8Value = CefV8Value::CreateNull();
//    if (!cefValue)
//    {
//        return v8Value;
//    }

//    auto type = cefValue->GetType();
//    switch (type)
//    {
//    case CefValueType::VTYPE_INVALID:
//    {
//        v8Value = CefV8Value::CreateUndefined();
//    }
//    break;
//    case CefValueType::VTYPE_NULL:
//    {
//        v8Value = CefV8Value::CreateNull();
//    }
//    break;
//    case CefValueType::VTYPE_BOOL:
//    {
//        auto v = cefValue->GetBool();
//        v8Value = CefV8Value::CreateBool(v);
//    }
//    break;
//    case CefValueType::VTYPE_INT:
//    {
//        auto v = cefValue->GetInt();
//        v8Value = CefV8Value::CreateInt(v);
//    }
//    break;
//    case CefValueType::VTYPE_DOUBLE:
//    {
//        auto v = cefValue->GetDouble();
//        v8Value = CefV8Value::CreateDouble(v);
//    } break;
//    case CefValueType::VTYPE_STRING:
//    {
//        auto v = cefValue->GetString();
//        v8Value = CefV8Value::CreateString(v);
//    } break;
//    case CefValueType::VTYPE_BINARY:
//    {
//      // TO-DO
//      // currently not supported
//    }
//    break;
//    case CefValueType::VTYPE_DICTIONARY:
//    {
//        auto cDict = cefValue->GetDictionary();
//        CefDictionaryValue::KeyList cKeys;
//        cDict->GetKeys(cKeys);
//        v8Value = CefV8Value::CreateObject(nullptr, nullptr);
//        for (auto& key : cKeys)
//        {
//            auto cVal = cDict->GetValue(key);
//            auto v8Val = CefValueToV8Value(cVal.get());
//            v8Value->SetValue(key, v8Val.get(), V8_PROPERTY_ATTRIBUTE_NONE);
//        }
//    }
//    break;
//    case CefValueType::VTYPE_LIST:
//    {
//        auto cList = cefValue->GetList();
//        int cCount = static_cast<int>(cList->GetSize());
//        v8Value = CefV8Value::CreateArray(static_cast<int>(cCount));
//        for (int i = 0; i < cCount; i++)
//        {
//            auto cVal = cList->GetValue(i);
//            auto v8Val = CefValueToV8Value(cVal.get());
//            v8Value->SetValue(i, v8Val.get());
//        }
//    }
//    break;
//    default:
//        break;
//    }

//    return v8Value;
//}

//CefRefPtr<CefValue> QCefRenderClient::V8ValueToCefValue(CefV8Value* v8Value)
//{
//    QCEF_DEBUG();

//    CefRefPtr<CefValue> cefValue = CefValue::Create();
//    if (!v8Value)
//    {
//        return cefValue;
//    }

//    if (v8Value->IsNull() || v8Value->IsUndefined())
//    {
//        cefValue->SetNull();
//    }
//    else if (v8Value->IsBool())
//    {
//        cefValue->SetBool(v8Value->GetBoolValue());
//    }
//    else if (v8Value->IsInt())
//    {
//        cefValue->SetInt(v8Value->GetIntValue());
//    }
//    else if (v8Value->IsUInt() || v8Value->IsDouble())
//    {
//        cefValue->SetDouble(v8Value->GetDoubleValue());
//    }
//    else if (v8Value->IsString())
//    {
//        cefValue->SetString(v8Value->GetStringValue());
//    }
//    else if (v8Value->IsArrayBuffer())
//    {
//      // TO-DO
//      // currently not supported
//    }
//    else if (v8Value->IsArray())
//    {
//        auto s = v8Value->GetArrayLength();
//        auto cefList = CefListValue::Create();
//        for (int i = 0; i < s; i++)
//        {
//            auto v8Val = v8Value->GetValue(i);
//            auto cefVal = V8ValueToCefValue(v8Val.get());
//            cefList->SetValue(i, cefVal);
//        }
//        cefValue->SetList(cefList);
//    }
//    else if (v8Value->IsObject())
//    {
//        CefDictionaryValue::KeyList keys;
//        v8Value->GetKeys(keys);
//        auto cefDict = CefDictionaryValue::Create();
//        for (auto& key : keys)
//        {
//            auto v8Val = v8Value->GetValue(key);
//            auto cefVal = V8ValueToCefValue(v8Val.get());
//            cefDict->SetValue(key, cefVal.get());
//        }
//        cefValue->SetDictionary(cefDict);
//    }
//    else
//    {
//        cefValue->SetNull();
//    }

//    return cefValue;
//}


